/*
 * Justin Prentice
 * TCSS 305
 * Tetris gui - gui
 */

package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BoxLayout;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.WindowConstants;

import controller.Board;

/**
 * Sets up the gui for Tetris.
 * @author Justin Prentice
 * @version 1.0
 */
public class GUI
{  
  /**
   * The default amount of time between board updates.  
   */
  public static final int DEFAULT_TIME_INTERVAL = 1000;
  
  /**
   * The minimum width of the window.
   */
  public static final int MINIMUM_WIDTH = 400;
  
  /**
   * The minimum height of the window.
   */
  public static final int MINIMUM_HEIGHT = 300;
  
  /**
   * How much faster the game should go per line cleared.
   */
  private static final int TIMER_DECREMENT = 5;
  
  /**
   * The number of milliseconds between color changes.
   */
  private static final int COLOR_INTERVAL = 50;
  
  /**
   * The default width of a tetris game.
   */
  private static final int DEFAULT_WIDTH = 10;
  
  /**
   * The default height of a tetris game.
   */
  private static final int DEFAULT_HEIGHT = 20;
  
  /**
   * A timer for making board updates.
   */
  private Timer my_timer;
  
  /**
   * A timer for changing the board's colors in zen mode.
   */
  private Timer my_color_timer;
  
  /**
   * A color interpreter to assign colors to blocks.
   */
  private ColorInterpreter my_color_interpreter;
  
  /**
   * An instance of a tetris board.
   */
  private Board my_board;
  
  /**
   * An instance of the board view object.
   */
  private BoardView my_board_view;
  
  /**
   * A preview panel to display upcoming piece, score, and level.
   */
  private PreviewPanel my_preview_panel;
  
  /**
   * Flags if the game is paused or not.
   */
  private boolean my_pause_state;
  
  /**
   * A music player to play background music.
   */
  //private SoundPlayer my_music_player;
  
  /**
   * Starts the GUI.
   */
  public void start()
  {
    final JFrame frame = new JFrame("Tetris");
    frame.setLayout(new BorderLayout());
    my_board = new Board();
    
    my_color_interpreter = new ColorInterpreter();
    my_preview_panel = new PreviewPanel(my_color_interpreter);
    my_board_view = new BoardView(my_color_interpreter);
    
    final JPanel sidebar = new JPanel();
    sidebar.setLayout(new BoxLayout(sidebar, BoxLayout.Y_AXIS));
    sidebar.add(my_preview_panel);
    
    sidebar.add(new JLabel("Left: Left Arrow"));
    sidebar.add(new JLabel("Right: Right Arrow"));
    sidebar.add(new JLabel("Down: Down Arrow"));
    sidebar.add(new JLabel("Rotate: Up Arrow"));
    sidebar.add(new JLabel("Drop: Spacebar"));
    sidebar.add(new JLabel("Pause: P"));
    sidebar.setBackground(Color.gray);
     
    frame.add(my_board_view, BorderLayout.CENTER);
    frame.add(sidebar, BorderLayout.EAST);
    
    my_board.addObserver(my_preview_panel);
    my_board.addObserver(my_board_view);    
    
    setUpListeners(frame);
    setUpMenu(frame);
    
    my_pause_state = false;
    //my_music_player = new SoundPlayer();
    //my_music_player.play("audio/Square.wav");
    
    frame.pack();
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
    my_timer.start();
  }
  /**
   * Interprets what to do with a key.  
   * @param the_key the keypress
   */
  public void interpretKey(final int the_key)
  {
    if (!my_board.isGameOver() && !my_pause_state) 
    {
      switch(the_key)
      {
        case KeyEvent.VK_LEFT:
          my_board.moveLeft();
          break;
        case KeyEvent.VK_RIGHT:
          my_board.moveRight();
          break;
        case KeyEvent.VK_DOWN:
          my_board.moveDown();
          break;
        case KeyEvent.VK_UP:
          my_board.rotate();
          break;
        case KeyEvent.VK_SPACE:
          my_board.drop();
          break;
        default:
      }
    }
    if (the_key == KeyEvent.VK_P)
    {
      pause();
    }
  }
  
  /**
   * Sets up listeners for the gui.
   * @param the_frame the frame to add listeners to
   */
  private void setUpListeners(final JFrame the_frame) //I disagree with complexity warning. 
  {
    //Timer setup
    my_timer = new Timer(DEFAULT_TIME_INTERVAL, new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        my_board.step();
        final Timer timer = (Timer) the_event.getSource();
        timer.setDelay(DEFAULT_TIME_INTERVAL - 
                       my_board.getUpdate().getScore() * TIMER_DECREMENT);
        if (my_board.isGameOver())
        {
          timer.stop();
          JOptionPane.showMessageDialog(the_frame, "You have been defeated!");
        }
      }
    });
    
    my_color_timer = new Timer(COLOR_INTERVAL, new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        my_color_interpreter.tick();
        my_board_view.repaint();
        my_preview_panel.repaint();
      }
    });
    
    //window resizing handling
    the_frame.addComponentListener(new ComponentAdapter()
    {
      @Override
      public void componentResized(final ComponentEvent the_event)
      {
        if (the_frame.getWidth() < MINIMUM_WIDTH)
        {
          the_frame.setSize(MINIMUM_WIDTH, the_frame.getHeight());
        }
        if (the_frame.getHeight() < MINIMUM_HEIGHT)
        {
          the_frame.setSize(the_frame.getWidth(), MINIMUM_HEIGHT);
        }
      }
    });
    
    //Stops timer if closed by x button
    the_frame.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosed(final WindowEvent the_event)
      {
        my_timer.stop();
        System.exit(0);
      }      
    });
   
    //Sets up keyListener
    the_frame.addKeyListener(new KeyListener() {
      @Override
      public void keyPressed(final KeyEvent the_event)
      {
        interpretKey(the_event.getKeyCode());
      }
      @Override
      public void keyReleased(final KeyEvent the_event)
      {
        //do nothing
      }

      @Override
      public void keyTyped(final KeyEvent the_event)
      {
         //do nothing
      }
      
    });
  }
  
  
  
  /**
   * Sets up the menu bar for the GUI.
   * @param the_frame the frame to recieve the new menu.
   */
  private void setUpMenu(final JFrame the_frame)
  {
    final JMenuBar menu = new JMenuBar();
    
    final JMenu file = new JMenu("File");
    
    final JMenuItem newgame = new JMenuItem("New Game");
    newgame.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        if (my_board.getUpdate().gameOver())
        {
          my_board.newGame(DEFAULT_WIDTH, DEFAULT_HEIGHT, null);
          my_timer.start();
        }
      }
    });
    
    final JMenuItem end = new JMenuItem("Surrender");
    end.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        my_board.surrender();
      }
    });
    
    final JMenuItem quit = new JMenuItem("Quit");
    quit.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        my_timer.stop();
        my_color_timer.stop();
        System.exit(0);
      }
    }); 
    
    file.add(newgame);
    file.add(end);
    file.add(quit);
    menu.add(file);
    
    final JMenu options = new JMenu("Options");
    final JCheckBoxMenuItem zenmode = new JCheckBoxMenuItem("Zen Mode", false);
    zenmode.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        if (((JCheckBoxMenuItem) the_event.getSource()).getState())
        {
          my_color_timer.start();
        }
        else
        {
          my_color_timer.stop();
          my_color_interpreter.reset();
        }
      }
    });
    
    options.add(zenmode);
    menu.add(options);
    
    the_frame.setJMenuBar(menu);
  }
  
  /**
   * Pauses the game.
   */
  private void pause()
  {
    my_pause_state ^= true; //recommended by PMD
    if (my_pause_state)
    {
      my_timer.stop();
    }
    else
    {
      my_timer.start();
    }
    my_board_view.setPaused(my_pause_state);
    my_board_view.repaint();
  }
  
}
